package de.hauschild.orbitvm.visualization;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.Point;
import java.awt.Toolkit;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.List;

import javax.swing.BoxLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.border.TitledBorder;

public class VMFrame extends JFrame {

  private static final long serialVersionUID = 8931924754135218216L;
  public static final int IMAGE_SIZE = 800;
  public static final int SIZE_FACTOR = 200000;

  private final JPanel controllerPanel;
  private final JLabel iterationLabel;
  private final JLabel scoreLabel;
  private final JLabel remainingFuelLabel;
  private final JLabel earthDistanceLabel;
  private final BufferedImage image = new BufferedImage(IMAGE_SIZE, IMAGE_SIZE, BufferedImage.TYPE_INT_RGB);
  private Graphics2D imageGraphics;
  private boolean earthDrawn;
  private final List<Point> pointsToClear = new ArrayList<Point>();

  public VMFrame() {
    super("Orbit virtual machine");
    setLayout(new BorderLayout());
    controllerPanel = new JPanel();
    controllerPanel.setLayout(new BoxLayout(controllerPanel, BoxLayout.PAGE_AXIS));
    controllerPanel.setPreferredSize(new Dimension(200, 800));

    iterationLabel = createControllerLabel("Time:");
    scoreLabel = createControllerLabel("Score:");
    remainingFuelLabel = createControllerLabel("Fuel remaining:");
    earthDistanceLabel = createControllerLabel("Distance to Earth:");

    add(controllerPanel, BorderLayout.LINE_START);

    final JPanel imagePanel = new JPanel() {
      private static final long serialVersionUID = 875845415680042715L;

      /**
       * {@inheritDoc}
       */
      @Override
      public void paint(final Graphics g) {
        super.paint(g);
        g.clearRect(0, 0, getBounds().width, getBounds().height);
        g.drawImage(image, 0, 0, null);
      }
    };
    add(imagePanel, BorderLayout.CENTER);

    setDefaultCloseOperation(EXIT_ON_CLOSE);
    setSize(1016, 838);
    final Dimension dim = Toolkit.getDefaultToolkit().getScreenSize();
    setBounds((dim.width - getWidth()) / 2, (dim.height - getHeight()) / 2, getWidth(), getHeight());
    setVisible(true);
  }

  public JLabel createControllerLabel(final String title) {
    final JPanel panel = new JPanel();
    panel.setBorder(new TitledBorder(title));
    final JLabel label = new JLabel();
    panel.add(label);
    controllerPanel.add(panel);
    return label;
  }

  public void drawPixel(final int x, final int y, final Color color) {
    // initialize graphics object
    if (imageGraphics == null) {
      imageGraphics = image.createGraphics();
    }
    // draw earth
    if (!earthDrawn) {
      final int earthRadius = 6357000 / SIZE_FACTOR;
      imageGraphics.setColor(Color.BLUE);
      imageGraphics.fillOval(IMAGE_SIZE / 2 - earthRadius, IMAGE_SIZE / 2 - earthRadius, 2 * earthRadius,
          2 * earthRadius);
      earthDrawn = true;
    }
    // draw current pixel
    imageGraphics.setColor(color);
    pixel(x, y);
    pointsToClear.add(new Point(x, y));
    // force repaint
    repaint();
  }

  public JPanel getControllerPanel() {
    return controllerPanel;
  }

  public JLabel getEarthDistanceLabel() {
    return earthDistanceLabel;
  }

  public Graphics2D getImageGraphics() {
    return imageGraphics;
  }

  public JLabel getIterationLabel() {
    return iterationLabel;
  }

  public JLabel getRemainingFuelLabel() {
    return remainingFuelLabel;
  }

  public JLabel getScoreLabel() {
    return scoreLabel;
  }

  public void startDraw() {
    // clear points
    if (imageGraphics != null) {
      imageGraphics.setColor(Color.BLACK);
      for (final Point point : pointsToClear) {
        pixel(point.x, point.y);
      }
      pointsToClear.clear();
    }
  }

  private void pixel(final int x, final int y) {
    imageGraphics.drawOval(x - 3, y - 3, 6, 6);
  }

}
